package com.xiguanlezz.cn.client.naming.remote.grpc.redo;

import com.xiguanlezz.cn.client.naming.remote.grpc.NamingGrpcClientProxy;
import com.xiguanlezz.cn.client.naming.remote.grpc.redo.data.InstanceRedoData;
import com.xiguanlezz.cn.client.naming.remote.grpc.redo.data.RedoData;
import com.xiguanlezz.cn.client.naming.remote.grpc.redo.data.SubscriberRedoData;
import com.xiguanlezz.cn.common.task.AbstractExecuteTask;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author：习惯了种种
 * @CreateDate：2024/11/25 15:28
 * @Description：重试的定时任务
 */
@Slf4j
public class RedoScheduledTask extends AbstractExecuteTask {
    // 客户端代理
    private final NamingGrpcClientProxy clientProxy;
    // 重试服务对象
    private final NamingGrpcRedoService redoService;


    public RedoScheduledTask(NamingGrpcClientProxy clientProxy, NamingGrpcRedoService redoService) {
        this.clientProxy = clientProxy;
        this.redoService = redoService;
    }


    @Override
    public void run() {
        try {
            redoForInstances();
            redoForSubscribes();
        } catch (Exception e) {
            log.error("Redo task run with unexpected exception: {}", e);
        }
    }

    // 执行和服务实例相关的重试操作的方法
    private void redoForInstances() {
        for (InstanceRedoData each : redoService.findInstanceRedoData()) {
            try {
                // 对每一个服务实例重试对象执行操作重试
                redoForInstance(each);
            } catch (Exception e) {
                log.error("Redo instance operation {} for {}@@{} failed. ",
                        each.getRedoType(),
                        each.getGroupName(),
                        each.getServiceName(),
                        e);
            }
        }
    }

    private void redoForInstance(InstanceRedoData data) throws Exception {
        String serviceName = data.getServiceName();
        String groupName = data.getGroupName();
        RedoData.RedoType redoType = data.getRedoType();
        switch (redoType) {
            case REGISTER:
                // 服务注册重试
                processRegisterRedoType(data, serviceName, groupName);
            case UNREGISTER:
                // 服务注销重试
                clientProxy.deregisterService(serviceName, groupName, data.getData());
            case REMOVE:
                redoService.removeInstanceForRedo(serviceName, groupName);
            default:
                break;
        }
    }

    private void processRegisterRedoType(InstanceRedoData redoData, String serviceName, String groupName) throws Exception {
        // 重新执行服务注册操作
        clientProxy.registerService(serviceName, groupName, redoData.getData());
    }

    private void redoForSubscribes() {
        for (SubscriberRedoData each : redoService.findSubscriberRedoData()) {
            try {
                redoForSubscribe(each);
            } catch (Exception e) {
                log.error("Redo subscriber operation {} for {}@@{}#{} failed. ",
                        each.getRedoType(), each.getGroupName(), each.getServiceName(),
                        each.getData(), e);
            }
        }
    }

    private void redoForSubscribe(SubscriberRedoData data) throws Exception {
        RedoData.RedoType redoType = data.getRedoType();
        String serviceName = data.getServiceName();
        String groupName = data.getGroupName();
        String cluster = data.getData();
        switch (redoType) {
            case REGISTER:
                if (isClientDisabled()) {
                    return;
                }
                clientProxy.doSubscribe(serviceName, groupName, cluster);
                break;
            case UNREGISTER:
                if (isClientDisabled()) {
                    return;
                }
                clientProxy.doUnsubscribe(serviceName, groupName, cluster);
                break;
            case REMOVE:
                redoService.removeSubscriberForRedo(data.getServiceName(), data.getGroupName(), data.getData());
                break;
            default:
        }
    }

    private boolean isClientDisabled() {
        return !clientProxy.isEnable();
    }

}
